#pragma once

#include "space\types.h"
#include "space\i_manager.h"
#include "space\i_lockable.h"
#include "space\entity.h"

#include <list>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <concurrent_queue.h>

namespace space {

	enum E_COLLECTION_OPERATION {
		PERFORM_INSERT,
		PERFORM_DELETE,
		E_COLLECTION_OPERATION_MAX
	};

	template<typename _T_>
	class collection : 
		public i_manager,
		protected std::mutex
	{
	public:
		_T_ find_by_id(const u_int64 id) const {
			std::list<_T_>::const_iterator iter;
			_T_ ptr = NULL;

			for(iter = _items.begin(); iter != _items.end(); iter++) {
				ptr = *iter;
				if(ptr->id() == id)
					break;
			}
			if(iter == _items.end())
				ptr = NULL;

			return ptr;
		}
		_T_ find_by_name(const std::string name) const  {
			_T_ ptr = NULL;
			std::unordered_map<std::string, _T_>::const_iterator hash_iter;
			std::list<_T_>::const_iterator iter;

			hash_iter = _hash.find(name);
			if(hash_iter != _hash.end()) {
				ptr = hash_iter->second;
			} else {
				// hard list search
				for(iter = _items.begin(); iter != _items.end(); iter++) {
					ptr = *iter;
					if(ptr->name() == name)
						break;
				}
				if(iter == _items.end())
					ptr = NULL;
			}
			

			return ptr;
		}

		typename std::list<_T_>::const_iterator iterator_by_id(const u_int64 id) const {
			std::list<_T_>::const_iterator iter;
			_T_ ptr = NULL;

			for(iter = _items.begin(); iter != _items.end(); iter++) {
				ptr = *iter;
				if(ptr->id() == id)
					break;
			}

			return iter;

		}
		typename std::unordered_map<std::string, _T_>::const_iterator iterator_by_name(const std::string name) const  {
			_T_ ptr = NULL;
			std::unordered_map<std::string, _T_>::const_iterator iter;
			for(iter = _hash.begin(); iter != _hash.end(); iter++) {
				if(iter->first == name)
					break;
			}

			return iter;
		}


		//
		// Thread safe insertion/deletion with updating functionality
		result add(_T_ ptr) {
			//_T_ obj = shared_ptr<i_bit>(ptr);
			_updates.push(_t_work_item(E_COLLECTION_OPERATION::PERFORM_INSERT, ptr));

			return RESULT_OK;
		}
		result remove(_T_ obj) {
			_updates.push(_t_work_item(E_COLLECTION_OPERATION::PERFORM_DELETE, obj));

			return RESULT_OK;
		}

		result _perform_updates(void) {
			_t_work_item item;

			while(_updates.try_pop(item)) {
				switch (item.op) {
				case E_COLLECTION_OPERATION::PERFORM_DELETE: 
					{
						LOG("Removing: [%s]", item.obj->name().c_str());
						_items.remove(item.obj);
						
						std::unordered_map<std::string, _T_>::iterator iter;
						iter = _hash.find(item.obj->name());
						if(iter != _hash.end() )
							_hash.erase(iter);
						//for(iter = _hash.begin(); iter != _hash.end(); iter++) {
						//	if(iter->first == item.obj->name() ) {
						//		_hash.erase(iter);
						//		break;
						//	}
						//}
					}
					break;
				case E_COLLECTION_OPERATION::PERFORM_INSERT: 
					{
						_items.push_back(item.obj);
						_hash[item.obj->name()] = item.obj;
					}
					break;
				default:
					throw -1;
				}
			}

			return RESULT_OK;
		}

		// get a vector of all the pointers
		std::vector<_T_> items(void) {
			std::vector<_T_> ret_items;
			std::list<_T_>::const_iterator iter;

			for(iter = _items.begin(); iter != _items.end(); iter++) {
				ret_items.push_back(*iter);
			}
			return ret_items;
		}

		result on_post_update(i_engine_ptr engine, float delta) { 
			// do all our actual updates here at the end
			return _perform_updates(); 
		}
		result on_pre_update(i_engine_ptr engine, float delta) { 
			return _perform_updates();
		}
		result on_update(i_engine_ptr engine, float delta) { return _perform_updates(); }

		result initialize(i_engine_ptr engine) { return RESULT_NOT_IMPL; }
		result release(i_engine_ptr engine) { return RESULT_NOT_IMPL; }

		_T_ operator[] (const u_int64 id) { return find_by_id(id); }
		_T_ operator[] (const std::string str) { return find_by_name(str); }
	protected:

	protected:
		struct _t_work_item {
			_t_work_item(){}
			_t_work_item(E_COLLECTION_OPERATION a, _T_ b) { op = a; obj=b; }
			E_COLLECTION_OPERATION op;
			_T_ obj;
		};
	protected:
		std::list<_T_> _items;
		std::unordered_map<std::string, _T_> _hash;
		concurrency::concurrent_queue<_t_work_item> _updates;
	};

};